﻿// -------------------------------------------------------------------------------------------------------------------------------
// <copyright file="SingleComplex.cs" company="Exul">
//     Copyright (c) Exul. All rights reserved.
// </copyright>
// <author>
//     Exul
// </author>
// -------------------------------------------------------------------------------------------------------------------------------

namespace ExulLibrary.Mathematics
{
    #region Usings

    using System;
    using System.Globalization;

    #endregion

    /// <summary>
    ///     Represents a complex number where each part is represented as single-precision floating-point value.
    /// </summary>
    [Serializable]
    public struct SingleComplex
    {
        #region Constants

        #region private

        /// <summary>
        ///     The logarithm by base 10 of exponent.
        /// </summary>
        private const float Logarithm10OfExponent = 0.43429448190325f;

        #endregion

        #endregion

        #region Fields

        #region public

        /// <summary>
        ///     The complex number with real part equal to zero and imaginary part equal to one.
        /// </summary>
        public static readonly SingleComplex ImaginaryOne = new SingleComplex(0, 1);

        /// <summary>
        ///     The complex number with real part equal to one and imaginary part equal to zero.
        /// </summary>
        public static readonly SingleComplex One = new SingleComplex(1, 0);

        /// <summary>
        ///     The complex number with real part equal to zero and imaginary part equal to zero.
        /// </summary>
        public static readonly SingleComplex Zero = new SingleComplex(0, 0);

        #endregion

        #region private

        /// <summary>
        ///     The imaginary part of complex number.
        /// </summary>
        private readonly float imaginary;

        /// <summary>
        ///     The real part of complex number.
        /// </summary>
        private readonly float real;

        #endregion

        #endregion

        #region Constructors and Destructors

        #region public

        /// <summary>
        ///     Initializes a new instance of the <see cref="SingleComplex"/> struct.
        /// </summary>
        /// <param name="real">
        ///     The real part of complex number.
        /// </param>
        /// <param name="imaginary">
        ///     The imaginary part of complex number.
        /// </param>
        public SingleComplex(float real, float imaginary)
        {
            this.real = real;
            this.imaginary = imaginary;
        }

        #endregion

        #endregion

        #region Properties

        #region public

        /// <summary>
        ///     Gets the imaginary component of the complex number.
        /// </summary>
        /// <value>
        ///     The imaginary component of the complex number.
        /// </value>
        public float Imaginary
        {
            get
            {
                return this.imaginary;
            }
        }

        /// <summary>
        ///     Gets the magnitude (or absolute value) of the complex number.
        /// </summary>
        /// <value>
        ///     The magnitude of the complex number.
        /// </value>
        public float Magnitude
        {
            get
            {
                return Abs(this);
            }
        }

        /// <summary>
        ///     Gets the phase of the complex number.
        /// </summary>
        /// <value>
        ///     The phase of the complex number, in radians.
        /// </value>
        public float Phase
        {
            get
            {
                return (float)Math.Atan2(this.imaginary, this.real);
            }
        }

        /// <summary>
        ///     Gets the real component of the complex number.
        /// </summary>
        /// <value>
        ///     The real component of the complex number.
        /// </value>
        public float Real
        {
            get
            {
                return this.real;
            }
        }

        #endregion

        #endregion

        #region Operators

        #region public

        /// <summary>
        ///     Adds two complex numbers.
        /// </summary>
        /// <param name="augend">
        ///     The augend value.
        /// </param>
        /// <param name="addend">
        ///     The addend value.
        /// </param>
        /// <returns>
        ///     The sum of <paramref name="augend"/> and <paramref name="addend"/>.
        /// </returns>
        public static SingleComplex operator +(SingleComplex augend, SingleComplex addend)
        {
            return new SingleComplex(augend.real + addend.real, augend.imaginary + addend.imaginary);
        }

        /// <summary>
        ///     Divides a complex number by another complex number.
        /// </summary>
        /// <param name="dividend">
        ///     The dividend value.
        /// </param>
        /// <param name="divisor">
        ///     The divisor value.
        /// </param>
        /// <returns>
        ///     The result of dividing <paramref name="dividend"/> by <paramref name="divisor"/>.
        /// </returns>
        public static SingleComplex operator /(SingleComplex dividend, SingleComplex divisor)
        {
            var dividendReal = dividend.real;
            var dividendImaginary = dividend.imaginary;
            var divisorReal = divisor.real;
            var divisorImaginary = divisor.imaginary;
            if (Math.Abs(divisorReal) <= Math.Abs(divisorImaginary))
            {
                var factor = divisorReal / divisorImaginary;
                var divisorFactor = divisorImaginary + (divisorReal * factor);
                return new SingleComplex(
                    (dividendImaginary + (dividendReal * factor)) / divisorFactor,
                    (-dividendReal + (dividendImaginary * factor)) / divisorFactor);
            }
            else
            {
                var factor = divisorImaginary / divisorReal;
                var divisorFactor = divisorReal + (divisorImaginary * factor);
                return new SingleComplex(
                    (dividendReal + (dividendImaginary * factor)) / divisorFactor,
                    (dividendImaginary - (dividendReal * factor)) / divisorFactor);
            }
        }

        /// <summary>
        ///     Compares two complex numbers on equality.
        /// </summary>
        /// <param name="left">
        ///     The first complex number to compare.
        /// </param>
        /// <param name="right">
        ///     The second complex number to compare.
        /// </param>
        /// <returns>
        ///     <see langword="true"/> if the <paramref name="left"/> and <paramref name="right"/> parameters are equal;
        ///     otherwise, <see langword="false"/>.
        /// </returns>
        public static bool operator ==(SingleComplex left, SingleComplex right)
        {
            if (Math.Abs(left.real - right.real) < float.Epsilon)
            {
                return false;
            }

            return Math.Abs(left.imaginary - right.imaginary) < float.Epsilon;
        }

        /// <summary>
        ///     Converts a decimal value to a complex number.
        /// </summary>
        /// <param name="value">
        ///     The value to convert to a complex number.
        /// </param>
        /// <returns>
        ///     A complex number that has real component equal to <paramref name="value"/> and imaginary component equal to zero.
        /// </returns>
        public static explicit operator SingleComplex(decimal value)
        {
            return new SingleComplex((float)value, 0);
        }

        /// <summary>
        ///     Converts a double-precision floating-point number to a complex number.
        /// </summary>
        /// <param name="value">
        ///     The value to convert to a complex number.
        /// </param>
        /// <returns>
        ///     A complex number that has real component equal to <paramref name="value"/> and imaginary component equal to zero.
        /// </returns>
        public static explicit operator SingleComplex(double value)
        {
            return new SingleComplex((float)value, 0);
        }

        /// <summary>
        ///     Converts a 16-bit signed integer to a complex number.
        /// </summary>
        /// <param name="value">
        ///     The value to convert to a complex number.
        /// </param>
        /// <returns>
        ///     A complex number that has real component equal to <paramref name="value"/> and imaginary component equal to zero.
        /// </returns>
        public static implicit operator SingleComplex(short value)
        {
            return new SingleComplex(value, 0);
        }

        /// <summary>
        ///     Converts a 32-bit signed integer to a complex number.
        /// </summary>
        /// <param name="value">
        ///     The value to convert to a complex number.
        /// </param>
        /// <returns>
        ///     A complex number that has real component equal to <paramref name="value"/> and imaginary component equal to zero.
        /// </returns>
        public static implicit operator SingleComplex(int value)
        {
            return new SingleComplex(value, 0);
        }

        /// <summary>
        ///     Converts a 64-bit signed integer to a complex number.
        /// </summary>
        /// <param name="value">
        ///     The value to convert to a complex number.
        /// </param>
        /// <returns>
        ///     A complex number that has real component equal to <paramref name="value"/> and imaginary component equal to zero.
        /// </returns>
        public static implicit operator SingleComplex(long value)
        {
            return new SingleComplex(value, 0);
        }

        /// <summary>
        ///     Converts a 16-bit unsigned integer to a complex number.
        /// </summary>
        /// <param name="value">
        ///     The value to convert to a complex number.
        /// </param>
        /// <returns>
        ///     A complex number that has real component equal to <paramref name="value"/> and imaginary component equal to zero.
        /// </returns>
        [CLSCompliant(false)]
        public static implicit operator SingleComplex(ushort value)
        {
            return new SingleComplex(value, 0);
        }

        /// <summary>
        ///     Converts a 32-bit unsigned integer to a complex number.
        /// </summary>
        /// <param name="value">
        ///     The value to convert to a complex number.
        /// </param>
        /// <returns>
        ///     A complex number that has real component equal to <paramref name="value"/> and imaginary component equal to zero.
        /// </returns>
        [CLSCompliant(false)]
        public static implicit operator SingleComplex(uint value)
        {
            return new SingleComplex(value, 0);
        }

        /// <summary>
        ///     Converts a 64-bit unsigned integer to a complex number.
        /// </summary>
        /// <param name="value">
        ///     The value to convert to a complex number.
        /// </param>
        /// <returns>
        ///     A complex number that has real component equal to <paramref name="value"/> and imaginary component equal to zero.
        /// </returns>
        [CLSCompliant(false)]
        public static implicit operator SingleComplex(ulong value)
        {
            return new SingleComplex(value, 0);
        }

        /// <summary>
        ///     Converts a signed byte to a complex number.
        /// </summary>
        /// <param name="value">
        ///     The value to convert to a complex number.
        /// </param>
        /// <returns>
        ///     A complex number that has real component equal to <paramref name="value"/> and imaginary component equal to zero.
        /// </returns>
        [CLSCompliant(false)]
        public static implicit operator SingleComplex(sbyte value)
        {
            return new SingleComplex(value, 0);
        }

        /// <summary>
        ///     Converts an unsigned byte to a complex number.
        /// </summary>
        /// <param name="value">
        ///     The value to convert to a complex number.
        /// </param>
        /// <returns>
        ///     A complex number that has real component equal to <paramref name="value"/> and imaginary component equal to zero.
        /// </returns>
        public static implicit operator SingleComplex(byte value)
        {
            return new SingleComplex(value, 0);
        }

        /// <summary>
        ///     Converts a single-precision floating-point number to a complex number.
        /// </summary>
        /// <param name="value">
        ///     The value to convert to a complex number.
        /// </param>
        /// <returns>
        ///     A complex number that has real component equal to <paramref name="value"/> and imaginary component equal to zero.
        /// </returns>
        public static implicit operator SingleComplex(float value)
        {
            return new SingleComplex(value, 0);
        }

        /// <summary>
        ///     Compares two complex number on inequality.
        /// </summary>
        /// <param name="left">
        ///     The first complex value to compare.
        /// </param>
        /// <param name="right">
        ///     The second complex value to compare.
        /// </param>
        /// <returns>
        ///     <see langword="true"/> if <paramref name="left"/> and <paramref name="right"/> are not equal;
        ///     otherwise, <see langword="false"/>.
        /// </returns>
        public static bool operator !=(SingleComplex left, SingleComplex right)
        {
            if (float.Epsilon < Math.Abs(left.real - right.real))
            {
                return true;
            }

            return float.Epsilon < Math.Abs(left.imaginary - right.imaginary);
        }

        /// <summary>
        ///     Multiplies two complex numbers.
        /// </summary>
        /// <param name="multiplicand">
        ///     The multiplicand value.
        /// </param>
        /// <param name="multiplier">
        ///     The multiplier value.
        /// </param>
        /// <returns>
        ///     The product of <paramref name="multiplicand"/> and <paramref name="multiplier"/>.
        /// </returns>
        public static SingleComplex operator *(SingleComplex multiplicand, SingleComplex multiplier)
        {
            return new SingleComplex(
                (multiplicand.real * multiplier.real) - (multiplicand.imaginary * multiplier.imaginary),
                (multiplicand.imaginary * multiplier.real) + (multiplicand.real * multiplier.imaginary));
        }

        /// <summary>
        ///     Subtracts a complex number from another complex number.
        /// </summary>
        /// <param name="minuend">
        ///     The minuend value.
        /// </param>
        /// <param name="subtrahend">
        ///     The subtrahend value.
        /// </param>
        /// <returns>
        ///     The result of subtracting <paramref name="subtrahend"/> from <paramref name="minuend"/>.
        /// </returns>
        public static SingleComplex operator -(SingleComplex minuend, SingleComplex subtrahend)
        {
            return new SingleComplex(minuend.real - subtrahend.real, minuend.imaginary - subtrahend.imaginary);
        }

        /// <summary>
        ///     Calculates additive inverse of a complex number.
        /// </summary>
        /// <param name="value">
        ///     The value to negate.
        /// </param>
        /// <returns>
        ///     The result of the <see cref="SingleComplex.Real"/> and <see cref="SingleComplex.Imaginary"/> components
        ///     of the <paramref name="value"/> parameter multiplied by -1.
        /// </returns>
        public static SingleComplex operator -(SingleComplex value)
        {
            return new SingleComplex(-value.real, -value.imaginary);
        }

        #endregion

        #endregion

        #region Overridden Methods

        #region public

        /// <summary>
        ///     Calculates a value that indicates whether the current instance and a specified object have the same value.
        /// </summary>
        /// <param name="obj">
        ///     The object to compare.
        /// </param>
        /// <returns>
        ///     <see langword="true"/> if the <paramref name="obj"/> parameter is a <see cref="SingleComplex"/> object or
        ///     a type capable of implicit conversion to a <see cref="SingleComplex"/> object, and
        ///     its value is equal to the current <see cref="SingleComplex"/> object; otherwise, <see langword="false"/>.
        /// </returns>
        public override bool Equals(object obj)
        {
            if (obj is SingleComplex)
            {
                return this == (SingleComplex)obj;
            }

            return false;
        }

        /// <summary>
        ///     Calculates the hash code for the complex number.
        /// </summary>
        /// <returns>
        ///     A 32-bit signed integer hash code.
        /// </returns>
        public override int GetHashCode()
        {
            var hashCode = this.real.GetHashCode() % 0x5f5e0fd;
            var hashCode1 = this.imaginary.GetHashCode();
            var num1 = hashCode ^ hashCode1;
            return num1;
        }

        /// <summary>
        ///     Converts the complex number to its equivalent string representation in Cartesian form.
        /// </summary>
        /// <returns>
        ///     The string representation of the complex number in Cartesian form.
        /// </returns>
        public override string ToString()
        {
            return string.Format(CultureInfo.CurrentCulture, "({0}, {1})", this.real, this.imaginary);
        }

        #endregion

        #endregion

        #region Methods

        #region public

        /// <summary>
        ///     Calculates the absolute value of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <returns>
        ///     The absolute value of <paramref name="value"/>.
        /// </returns>
        public static float Abs(SingleComplex value)
        {
            if (float.IsInfinity(value.real) || float.IsInfinity(value.imaginary))
            {
                return float.PositiveInfinity;
            }

            var realValue = Math.Abs(value.real);
            var imaginaryValue = Math.Abs(value.imaginary);
            if (realValue <= imaginaryValue)
            {
                if (float.Epsilon < imaginaryValue)
                {
                    var division = realValue / imaginaryValue;
                    return (float)(imaginaryValue * Math.Sqrt(1 + (division * division)));
                }

                return realValue;
            }

            var division2 = imaginaryValue / realValue;
            return (float)(realValue * Math.Sqrt(1 + (division2 * division2)));
        }

        /// <summary>
        ///     Calculates the angle that is the arc cosine of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number that represents a cosine.
        /// </param>
        /// <returns>
        ///     The angle, measured in radians, which is the arc cosine of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Acos(SingleComplex value)
        {
            return -ImaginaryOne * Log(value + (ImaginaryOne * Sqrt(One - (value * value))));
        }

        /// <summary>
        ///     Adds two complex numbers.
        /// </summary>
        /// <param name="augend">
        ///     The augend value.
        /// </param>
        /// <param name="addend">
        ///     The addend value.
        /// </param>
        /// <returns>
        ///     The sum of <paramref name="augend"/> and <paramref name="addend"/>.
        /// </returns>
        public static SingleComplex Add(SingleComplex augend, SingleComplex addend)
        {
            return augend + addend;
        }

        /// <summary>
        ///     Calculates the angle that is the arc sine of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number that represents a sine.
        /// </param>
        /// <returns>
        ///     The angle, measured in radians, which is the arc sine of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Asin(SingleComplex value)
        {
            return -ImaginaryOne * Log((ImaginaryOne * value) + Sqrt(One - (value * value)));
        }

        /// <summary>
        ///     Calculates the angle that is the arc tangent of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number that represents a tangent.
        /// </param>
        /// <returns>
        ///     The angle, measured in radians, which is the arc tangent of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Atan(SingleComplex value)
        {
            var two = new SingleComplex(2, 0);
            return ImaginaryOne / two * (Log(One - (ImaginaryOne * value)) - Log(One + (ImaginaryOne * value)));
        }

        /// <summary>
        ///     Calculates the conjugate of a complex number.
        /// </summary>
        /// <param name="value">
        ///     The conjugate of <paramref name="value"/>.
        /// </param>
        /// <returns>
        ///     A complex number that has the real part equal to the real part of <paramref name="value"/> and
        ///     the imaginary part equal to the imaginary part of <paramref name="value"/> multiplied by -1.
        /// </returns>
        public static SingleComplex Conjugate(SingleComplex value)
        {
            return new SingleComplex(value.real, -value.imaginary);
        }

        /// <summary>
        ///     Calculates the cosine of a complex number.
        /// </summary>
        /// <param name="value">
        ///    A complex number.
        /// </param>
        /// <returns>
        ///     A complex number that represents the cosine of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Cos(SingleComplex value)
        {
            var realValue = value.real;
            var imaginaryValue = value.imaginary;
            return new SingleComplex(
                (float)(Math.Cos(realValue) * Math.Cosh(imaginaryValue)),
                (float)(-(Math.Sin(realValue) * Math.Sinh(imaginaryValue))));
        }

        /// <summary>
        ///     Calculates the hyperbolic cosine of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <returns>
        ///     A complex number that represents the hyperbolic cosine of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Cosh(SingleComplex value)
        {
            var realValue = value.real;
            var imaginaryValue = value.imaginary;
            return new SingleComplex(
                (float)(Math.Cosh(realValue) * Math.Cos(imaginaryValue)),
                (float)(Math.Sinh(realValue) * Math.Sin(imaginaryValue)));
        }

        /// <summary>
        ///     Divides one complex number by another.
        /// </summary>
        /// <param name="dividend">
        ///     The dividend value.
        /// </param>
        /// <param name="divisor">
        ///     The divisor value.
        /// </param>
        /// <returns>
        ///     The quotient of the division of <paramref name="dividend"/> by <paramref name="divisor"/>.
        /// </returns>
        public static SingleComplex Divide(SingleComplex dividend, SingleComplex divisor)
        {
            return dividend / divisor;
        }

        /// <summary>
        ///     Calculates E raised to the power specified by a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number that specifies a power.
        /// </param>
        /// <returns>
        ///     The number E raised to the power <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Exp(SingleComplex value)
        {
            var realExp = Math.Exp(value.real);
            return new SingleComplex(
                (float)(realExp * Math.Cos(value.imaginary)),
                (float)(realExp * Math.Sin(value.imaginary)));
        }

        /// <summary>
        ///     Creates a complex number from a point's polar coordinates.
        /// </summary>
        /// <param name="magnitude">
        ///     The magnitude, which is the distance from the intersection of the x-axis and the y-axis to the number.
        /// </param>
        /// <param name="phase">
        ///     The phase, which is the angle from the line to the horizontal axis, measured in radians.
        /// </param>
        /// <returns>
        ///     A complex number converted from a point's polar coordinates.
        /// </returns>
        public static SingleComplex FromPolarCoordinates(float magnitude, float phase)
        {
            return new SingleComplex((float)(magnitude * Math.Cos(phase)), (float)(magnitude * Math.Sin(phase)));
        }

        /// <summary>
        ///     Calculates the natural logarithm of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <returns>
        ///     The natural logarithm of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Log(SingleComplex value)
        {
            return new SingleComplex((float)Math.Log(Abs(value)), (float)Math.Atan2(value.imaginary, value.real));
        }

        /// <summary>
        ///     Calculates the logarithm of a complex number in a specified base.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <param name="baseValue">
        ///     The base of the logarithm.
        /// </param>
        /// <returns>
        ///     The logarithm of <paramref name="value"/> in base <paramref name="baseValue"/>.
        /// </returns>
        public static SingleComplex Log(SingleComplex value, float baseValue)
        {
            return Log(value) / Log(baseValue);
        }

        /// <summary>
        ///     Returns the base-10 logarithm of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <returns>
        ///     The base-10 logarithm of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Log10(SingleComplex value)
        {
            return Scale(Log(value), Logarithm10OfExponent);
        }

        /// <summary>
        ///     Calculates the product of two complex numbers.
        /// </summary>
        /// <param name="multiplicand">
        ///     The multiplicand value.
        /// </param>
        /// <param name="multiplier">
        ///     The multiplier value.
        /// </param>
        /// <returns>
        ///     The product of the <paramref name="multiplicand"/> and <paramref name="multiplier"/> parameters.
        /// </returns>
        public static SingleComplex Multiply(SingleComplex multiplicand, SingleComplex multiplier)
        {
            return multiplicand * multiplier;
        }

        /// <summary>
        ///     Calculates the additive inverse of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <returns>
        ///     The result of the <see cref="SingleComplex.Real"/> and <see cref="SingleComplex.Imaginary"/> components of
        ///     the <paramref name="value"/> parameter multiplied by -1.
        /// </returns>
        public static SingleComplex Negate(SingleComplex value)
        {
            return -value;
        }

        /// <summary>
        ///     Calculates a complex number raised to a power specified by a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number to be raised to a power.
        /// </param>
        /// <param name="power">
        ///     A complex number that specifies a power.
        /// </param>
        /// <returns>
        ///     The complex number <paramref name="value"/> raised to the power <paramref name="power"/>.
        /// </returns>
        public static SingleComplex Pow(SingleComplex value, SingleComplex power)
        {
            if (power == Zero)
            {
                return One;
            }

            if (value == Zero)
            {
                return Zero;
            }

            var valueReal = value.real;
            var valueImaginary = value.imaginary;
            var powerReal = power.real;
            var powerImaginary = power.imaginary;
            var magnitudeValue = Abs(value);
            var tangent = Math.Atan2(valueImaginary, valueReal);
            var factor = (powerReal * tangent) + (powerImaginary * Math.Log(magnitudeValue));
            var factor2 = Math.Pow(magnitudeValue, powerReal) * Math.Pow(Math.E, -powerImaginary * tangent);
            return new SingleComplex((float)(factor2 * Math.Cos(factor)), (float)(factor2 * Math.Sin(factor)));
        }

        /// <summary>
        ///     Calculates a complex number raised to a power specified by a single-precision floating-point number.
        /// </summary>
        /// <param name="value">
        ///     A complex number to be raised to a power.
        /// </param>
        /// <param name="power">
        ///     A single-precision floating-point number that specifies a power.
        /// </param>
        /// <returns>
        ///     The complex number <paramref name="value"/> raised to the power <paramref name="power"/>.
        /// </returns>
        public static SingleComplex Pow(SingleComplex value, float power)
        {
            return Pow(value, new SingleComplex(power, 0));
        }

        /// <summary>
        ///     Calculates the multiplicative inverse of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <returns>
        ///     The reciprocal of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Reciprocal(SingleComplex value)
        {
            return (float.Epsilon < Math.Abs(value.real)) || (float.Epsilon < Math.Abs(value.imaginary))
                       ? One / value
                       : Zero;
        }

        /// <summary>
        ///     Scales each part of a complex number by single-precision floating-point number.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <param name="factor">
        ///     A factor to multiply.
        /// </param>
        /// <returns>
        ///     A result of scaling each part of <paramref name="value"/> by <paramref name="factor"/>.
        /// </returns>
        public static SingleComplex Scale(SingleComplex value, float factor)
        {
            return new SingleComplex(factor * value.real, factor * value.imaginary);
        }

        /// <summary>
        ///     Calculates the sine of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <returns>
        ///     The sine of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Sin(SingleComplex value)
        {
            var realValue = value.real;
            var imaginaryValue = value.imaginary;
            return new SingleComplex(
                (float)(Math.Sin(realValue) * Math.Cosh(imaginaryValue)),
                (float)(Math.Cos(realValue) * Math.Sinh(imaginaryValue)));
        }

        /// <summary>
        ///     Calculates the hyperbolic sine of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <returns>
        ///     The hyperbolic sine of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Sinh(SingleComplex value)
        {
            var realValue = value.real;
            var imaginaryValue = value.imaginary;
            return new SingleComplex(
                (float)(Math.Sinh(realValue) * Math.Cos(imaginaryValue)),
                (float)(Math.Cosh(realValue) * Math.Sin(imaginaryValue)));
        }

        /// <summary>
        ///     Calculates the square root of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <returns>
        ///     The square root of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Sqrt(SingleComplex value)
        {
            return FromPolarCoordinates((float)Math.Sqrt(value.Magnitude), value.Phase / 2);
        }

        /// <summary>
        ///     Subtracts one complex number from another.
        /// </summary>
        /// <param name="minuend">
        ///     The minuend value.
        /// </param>
        /// <param name="subtrahend">
        ///     The subtrahend value.
        /// </param>
        /// <returns>
        ///     The result of subtracting <paramref name="subtrahend"/> from <paramref name="minuend"/>.
        /// </returns>
        public static SingleComplex Subtract(SingleComplex minuend, SingleComplex subtrahend)
        {
            return minuend - subtrahend;
        }

        /// <summary>
        ///     Calculates the tangent of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <returns>
        ///     The tangent of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Tan(SingleComplex value)
        {
            return Sin(value) / Cos(value);
        }

        /// <summary>
        ///     Calculates the hyperbolic tangent of a complex number.
        /// </summary>
        /// <param name="value">
        ///     A complex number.
        /// </param>
        /// <returns>
        ///     The hyperbolic tangent of <paramref name="value"/>.
        /// </returns>
        public static SingleComplex Tanh(SingleComplex value)
        {
            return Sinh(value) / Cosh(value);
        }

        /// <summary>
        ///     Calculates a value that indicates whether the current instance and a specified complex number have the same value.
        /// </summary>
        /// <param name="value">
        ///     A complex number to compare.
        /// </param>
        /// <returns>
        ///     <see langword="true"/> if this complex number and <paramref name="value"/> have the same value;
        ///     otherwise, <see langword="false"/>.
        /// </returns>
        public bool Equals(SingleComplex value)
        {
            return this.real.Equals(value.real) && this.imaginary.Equals(value.imaginary);
        }

        /// <summary>
        ///     Converts the complex number to its equivalent string representation in Cartesian form.
        /// </summary>
        /// <param name="format">
        ///     A numeric format string.
        /// </param>
        /// <returns>
        ///     The string representation of the complex number in Cartesian form.
        /// </returns>
        /// <exception cref="FormatException">
        ///     <paramref name="format"/> is not a valid format string.
        /// </exception>
        public string ToString(string format)
        {
            return string.Format(
                CultureInfo.CurrentCulture,
                "({0}, {1})",
                this.real.ToString(format, CultureInfo.CurrentCulture),
                this.imaginary.ToString(format, CultureInfo.CurrentCulture));
        }

        /// <summary>
        ///     Converts the complex number to its equivalent string representation in Cartesian form.
        /// </summary>
        /// <param name="provider">
        ///     An object that supplies culture-specific formatting information.
        /// </param>
        /// <returns>
        ///     The string representation of the complex number in Cartesian form.
        /// </returns>
        public string ToString(IFormatProvider provider)
        {
            return string.Format(provider, "({0}, {1})", this.real, this.imaginary);
        }

        /// <summary>
        ///     Converts the complex number to its equivalent string representation in Cartesian form.
        /// </summary>
        /// <param name="format">
        ///     A numeric format string.
        /// </param>
        /// <param name="provider">
        ///     An object that supplies culture-specific formatting information.
        /// </param>
        /// <returns>
        ///     The string representation of the current instance in Cartesian form.
        /// </returns>
        /// <exception cref="FormatException">
        ///     <paramref name="format"/> is not a valid format string.
        /// </exception>
        public string ToString(string format, IFormatProvider provider)
        {
            return string.Format(
                provider, "({0}, {1})", this.real.ToString(format, provider), this.imaginary.ToString(format, provider));
        }

        #endregion

        #endregion
    }
}